/*
 * @ProjectName: 编程学习
 * @Copyright:   2019 HangZhou Ashe Dev, Ltd. All Right Reserved.
 * @address:     https://yiyuery.github.io/NoteBooks/
 * @date:        2020/2/24 12:07 上午
 * @description: 本内容仅限于编程技术学习使用，转发请注明出处.
 */
package com.yi.yier.boot.autoconfigure.codegenerator.common;

import com.yi.yier.boot.autoconfigure.codegenerator.gen.AbstractCodeGenerator;
import com.yi.yier.common.util.string.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.map.LinkedMap;
import org.apache.commons.io.FileUtils;
import org.apache.ibatis.io.Resources;
import org.apache.velocity.runtime.resource.loader.ResourceLoaderFactory;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.UrlResource;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.lang.System.in;

/**
 * <p>
 *
 * </p>
 *
 * @author Yiyuery
 * @version V1.0.0
 * @date 2020/2/24 12:07 上午
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify By: {修改人}  2020/2/24
 * @modify reason: {方法名}:{原因}
 * ...
 */
@Slf4j
public class PropertiesLoader {


    private static Properties props;

    private static Map<String, String> propMap = new HashMap<>();

    public static Properties getProps() {
        return props;
    }

    public static Map<String, String> getPropMap() {
        return propMap;
    }

    public static void init() {
        loadProperties();
        appendProperties();
    }


    private static void appendProperties() {

        JDBCConnectionConfiguration conn = loadDbProperties();
        //数据库
        props.setProperty("db.url", conn.getConnectionURL());
        props.setProperty("db.username", conn.getUserId());
        props.setProperty("db.password", conn.getPassword());
        props.setProperty("db.driver", conn.getDriverClass());

        //模板配置
        String templateLocation = getProperty(PropertyConstant.YIER_GEN_PROP_TEMPLATE_LOCATION);
        String templateType = getProperty(PropertyConstant.YIER_GEN_PROP_TEMPLATE_TYPE);
        URL uri = PropertiesLoader.class.getResource(templateLocation);
        try {
            Path path = Paths.get(uri.toURI());
            if (StringUtils.isEmpty(templateLocation)) {
                templateLocation = getDefaultTemplateFilePath();
            }
            props.setProperty(PropertyConstant.YIER_GEN_PROP_TEMPLATE_LOCATION, Paths.get(templateLocation, templateType).toAbsolutePath().toString());
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    private static String getDefaultTemplateFilePath() {
        String templatePath = "";
        Enumeration<URL> resources = null;
        try {
            resources = PropertiesLoader.class.getClassLoader().getResources("codegenerator");
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                UrlResource resource = new UrlResource(url);
                try {
                    templatePath = resource.getURI().getPath();
                } catch (IOException e) {
                    log.error("模板配置加载失败");
                }
            }
        } catch (IOException e) {
            log.error("模板配置加载失败");
        }
        return templatePath;
    }

    private static JDBCConnectionConfiguration loadDbProperties() {
        JDBCConnectionConfiguration coon = new JDBCConnectionConfiguration();
        coon.setConnectionURL(getProperty(PropertyConstant.YIER_GEN_PROP_JDBC_URL));
        coon.setDriverClass(getProperty(PropertyConstant.YIER_GEN_PROP_JDBC_DRIVER));
        coon.setUserId(getProperty(PropertyConstant.YIER_GEN_PROP_JDBC_USERNAME));
        coon.setPassword(getProperty(PropertyConstant.YIER_GEN_PROP_JDBC_PASSWORD));
        return coon;
    }

    /**
     * 加载配置文件
     *
     * @return
     */
    private static void loadProperties() {
        try {

            // 加载yml中定义的配置并props中实现自动拼接
            loadBasicPropsForGenerator();
            //补充Props中类名简写
            parserClassSimplyName();
            //解析自定义 key
            parserBasicPropKey();
        } catch (Exception e) {
            throw new RuntimeException("加载配置文件异常!", e);
        }
    }

    private static void parserBasicPropKey() {
        Iterator<Map.Entry<String, String>> iterator = getPropMap().entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> next = iterator.next();
                if (next.getValue().contains(PropertyConstant.DEFAULT_KEY_PROJECT_KEY)) {
                    getPropMap().put(next.getKey() ,next.getValue().replace(PropertyConstant.DEFAULT_KEY_PROJECT_KEY, System.getProperty("user.dir")));
                }
        }
        props.putAll(getPropMap());
    }

    private static void parserClassSimplyName() {
        Iterator<Map.Entry<String, String>> iterator = getPropMap().entrySet().iterator();
        Map<String, String> tempMap = new HashMap<>();
        while (iterator.hasNext()) {
            Map.Entry<String, String> next = iterator.next();
            if (next.getKey().endsWith("-reference")) {
                String[] split = next.getValue().split("\\.");
                if (split.length > 0) {
                    tempMap.put(next.getKey()+ "-name", split[split.length - 1]);
                }
            }
        }
        getPropMap().putAll(tempMap);
        props.putAll(getPropMap());
    }

    private static void loadBasicPropsForGenerator() throws IOException {
        props = new Properties();
        YamlPropertySourceLoader ymlLoader = new YamlPropertySourceLoader();
        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
        resourceLoader.setClassLoader(AbstractCodeGenerator.class.getClassLoader());
        List<PropertySource<?>> propertySourceList = ymlLoader.load("yier.gen", resourceLoader.getResource("codegenerator/yier-gen.yml"));
        Map<String, Object> propMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(propertySourceList)) {
            propertySourceList.forEach(propertySource -> {
                propMap.putAll((Map<? extends String, ?>) propertySource.getSource());
            });
        }
        if (MapUtils.isNotEmpty(propMap)) {
            Set<Map.Entry<String, Object>> entries = propMap.entrySet();
            Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
                if (entry.getKey().toString().contains("package-")&& !entry.getKey().contains("package-base")) {
                    StringBuilder strVal = new StringBuilder();
                    String key = entry.getKey();
                    String[] split = key.split("-");
                    String prefixKey = "";
                    for (String e : split) {
                        if (prefixKey.length() != 0) {
                            prefixKey += "-" + e;
                        } else {
                            prefixKey += "" + e;
                        }
                        if (propMap.containsKey(prefixKey)) {
                            String value = propMap.get(prefixKey).toString();
                            strVal.append(value);
                        }
                    }
                    if (StringUtils.isEmpty(strVal.toString()) ) {
                        getPropMap().put(entry.getKey(), propMap.get(PropertyConstant.YIER_GEN_PROP_PACKAGE_BASE).toString() + entry.getValue().toString());
                    } else {
                        getPropMap().put(entry.getKey(), propMap.get(PropertyConstant.YIER_GEN_PROP_PACKAGE_BASE).toString() + strVal.toString());
                    }
                } else {
                    getPropMap().put(entry.getKey(), entry.getValue().toString());
                }
            }
        }
        props.putAll(getPropMap());
    }

    /**
     * 包转成路径
     * eg: com.bigsea.sns ==> com/bigsea/sns
     *
     * @param packageName
     * @return
     */
    private static String packageConvertPath(String packageName) {
        return String.format("/%s/", packageName.contains(".") ? packageName.replaceAll("\\.", "/") : packageName);
    }


    public static String getProperty(String key) {
        if (StringUtils.isEmpty(props.get(key))) {
            log.warn(String.format("key %s is not exist!", key));
            return "";
        }
        return props.get(key).toString();
    }

    public static String getPropertyOrDefault(String key, String defaultVal) {
        return StringUtils.isEmpty(props.get(key)) ? defaultVal : getProperty(key);
    }

}
